package com.happycat.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.happycat.filters.JsonAuthenticationFilter;
import com.happycat.handler.AccessFailHandler;
import com.happycat.handler.HappyCatAuthenticationEntryPoint;
import com.happycat.handler.LoginFailHandler;
import com.happycat.handler.LoginSuccessHandler;
import com.happycat.manage.HappyCatAccessDecisionManager;
import com.happycat.provider.HappyCatAuthenticationProvider;
import com.happycat.service.impl.UserDetailServiceImpl;

@EnableWebSecurity
public class HappyCatSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private UserDetailServiceImpl userDetailServiceImpl;

	@Autowired
	private HappyCatSecurity happyCatSecurity;

	@Autowired
	private HappyCatAuthenticationProvider happyCatAuthenticationProvider;

	@Autowired
	private HappyCatAccessDecisionManager happyCatAccessDecisionManager;

	@Autowired
	private AccessFailHandler accessFailHandler;
	@Autowired
	private HappyCatAuthenticationEntryPoint happyCatAuthenticationEntryPoint;
	@Autowired
	private LoginFailHandler loginFailHandler;
	@Autowired
	private LoginSuccessHandler loginSuccessHandler;

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		/**
		 * 指定用户认证时，默认从哪里获取认证用户信息
		 */
		// auth.userDetailsService(userDetailServiceImpl);
	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers(happyCatSecurity.getStaticResource());
	}

	/**
	 * Http安全配置
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {

	    //自定义过滤器认证用户名密码
		http.formLogin().failureHandler(loginFailHandler).successHandler(loginSuccessHandler);

		http.exceptionHandling().accessDeniedHandler(accessFailHandler)
				.authenticationEntryPoint(happyCatAuthenticationEntryPoint);

		http.addFilterAt(jsonAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
		http.authenticationProvider(happyCatAuthenticationProvider);
		http.userDetailsService(userDetailServiceImpl);

		ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();

		//使用token, 不需要csrf
		http.csrf().disable().cors();
		//基于token, 不需要session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        //自动放行的url
		registry.antMatchers(happyCatSecurity.getAntMatchers()).permitAll();

        //其它全部需要认证
		registry.anyRequest().authenticated();
		registry.and().headers().frameOptions().disable();
		registry.accessDecisionManager(happyCatAccessDecisionManager);

		/*
		 * http .cors().and() .antMatcher("/**").authorizeRequests() .antMatchers("/",
		 * "/login**").permitAll() .anyRequest().authenticated()
		 * //这里必须要写formLogin()，不然原有的UsernamePasswordAuthenticationFilter不会出现，
		 * 也就无法配置我们重新的UsernamePasswordAuthenticationFilter
		 * .and().formLogin().loginPage("/") .and().csrf().disable();
		 * http.addFilterAt(jsonAuthenticationFilter(),
		 * UsernamePasswordAuthenticationFilter.class);// 需要身份认证
		 */
	}

	/**
	 * 密码加密器
	 */
	@Bean
	public PasswordEncoder passwordEncoder() {
		/**
		 * BCryptPasswordEncoder：相同的密码明文每次生成的密文都不同，安全性更高
		 */
		return new BCryptPasswordEncoder();
	}

	@Bean
	public JsonAuthenticationFilter jsonAuthenticationFilter() throws Exception {
		JsonAuthenticationFilter filter = new JsonAuthenticationFilter();
		filter.setAuthenticationSuccessHandler(loginSuccessHandler);
		filter.setAuthenticationFailureHandler(loginFailHandler);
		filter.setFilterProcessesUrl("/login");

		// 这句很关键，重用WebSecurityConfigurerAdapter配置的AuthenticationManager，不然要自己组装AuthenticationManager
		filter.setAuthenticationManager(authenticationManagerBean());
		return filter;
	}



}
